package com.mega.common.security.filter.filters;

import cn.hutool.json.JSONUtil;
import com.mega.common.core.constant.CacheConstants;
import com.mega.common.core.constant.Constants;
import com.mega.common.core.constant.HttpStatus;
import com.mega.common.core.enums.CommonMsgEnum;
import com.mega.common.core.exception.BusinessException;
import com.mega.common.core.i18n.msg.ServerExceptionMsgService;
import com.mega.common.core.utils.SpringUtils;
import com.mega.common.core.utils.StringUtils;
import com.mega.common.redis.service.RedisService;
import com.mega.system.api.vo.LoginUser;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 权限过滤器
 */
@Slf4j
public class AuthFilter implements Filter {

    /**
     * 失效时间
     */
    private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;

    /**
     * 默认排除url
     */
    private final String defauleExcludeUrls = "/*.html,/*.css,/*.js,/swagger-resources,/v2/api-docs,/login,/log";

    /**
     * 排除链接
     */
    public List<String> excludes = new ArrayList<>();

    /**
     * redis缓存
     */
    private RedisService redisService;

    /**
     * 异常消息
     */
    private ServerExceptionMsgService serverExceptionMsgService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String tempExcludes = filterConfig.getInitParameter("excludes");
        if (StringUtils.isNotEmpty(tempExcludes)) {
            String[] url = tempExcludes.split(",");
            for (int i = 0; url != null && i < url.length; i++) {
                excludes.add(url[i]);
            }
        }
        excludes.addAll(Arrays.asList(defauleExcludeUrls.split(",")));
        redisService = SpringUtils.getBean(RedisService.class);
        serverExceptionMsgService = SpringUtils.getBean(ServerExceptionMsgService.class);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String url = request.getRequestURI();

        // 跳过不需要验证的路径
        if (StringUtils.matches(url, excludes)) {
            filterChain.doFilter(request, response);
        } else {
            String token = getToken(request);
            if (StringUtils.isBlank(token)) {
                setUnauthorizedResponse(response, new BusinessException(CommonMsgEnum.NO_TOKEN_REQUEST));
                return;
            }

            String key = getTokenKey(token);
            LoginUser loginUser = redisService.getCacheObject(key);
            if (StringUtils.isNull(loginUser)) {
                setUnauthorizedResponse(response, new BusinessException(CommonMsgEnum.AUTHENTICATION_EXPIRED));
                return;
            }

            String userid = String.valueOf(loginUser.getUserId());
            String username = loginUser.getUserName();
            if (StringUtils.isBlank(userid) || StringUtils.isBlank(username)) {
                setUnauthorizedResponse(response, new BusinessException(CommonMsgEnum.AUTHENTICATION_FAIL, url));
                return;
            }
            // 设置过期时间
            redisService.expire(key, EXPIRE_TIME);
            RepeatedlyRequestWrapper requestWrapper = null;
            if (request instanceof RepeatedlyRequestWrapper) {
                requestWrapper = (RepeatedlyRequestWrapper) request;
            } else {
                requestWrapper = new RepeatedlyRequestWrapper(request, response);
            }
            requestWrapper.addHeader(CacheConstants.DETAILS_USER_ID, userid);
            requestWrapper.addHeader(CacheConstants.DETAILS_USERNAME, username);
            filterChain.doFilter(requestWrapper, response);
        }
    }

    /**
     * 返回对象
     *
     * @param response
     * @param businessException
     */
    private void setUnauthorizedResponse(HttpServletResponse response, BusinessException businessException) {
        try {
            response.setStatus(HttpStatus.UNAUTHORIZED);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(JSONUtil.toJsonStr(serverExceptionMsgService.getExceptionMessage(businessException)));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取redis缓存key
     *
     * @param token
     * @return
     */
    private String getTokenKey(String token) {
        return CacheConstants.LOGIN_TOKEN_KEY + token;
    }

    /**
     * 获取请求token
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(CacheConstants.HEADER);
        if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX)) {
            token = token.replace(CacheConstants.TOKEN_PREFIX, "");
        }
        return token;
    }
}
